﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Windows;

using GameLibrary;
using GameLibrary.Player;
using GameLibrary.Unit;
using GameLibrary.Map;
using GameLibrary.Settlement;
using GameLibrary.Tile;

namespace UserInterface.Presenters
{
    using Helpers.Graph;
    using Helpers;
    using Model;

    [Serializable]
    public class HumanPlayerCoordinator
    {
        HumPlayer Player = null;

        internal int MapHeight
        {
            get { return GMHelper.Height; }
        }

        internal int MapWidth
        {
            get { return GMHelper.Width; }
        }

        public HumanPlayerCoordinator()
        {}
        
        internal void SetHumanPlayer(HumPlayer player)
        {
            this.Player = player;
        }

        internal IEnumerable<UnitInfo> GetUnitsByPosition(Position pos)
        {
            return Player.GetUnitInfosByPosition(pos);
        }

        internal void MoveUnitToPosition(UnitInfo unit, Position to)
        {
            this.Player.MoveUnitToPosition(unit, to);
        }

        private Graph GetGraphFrom2DArray(double[,] map, Position from)
        {
         //   Graph graph = new Graph();
            return null;
        }

        private IEnumerable<Position> FindNearbyPositions(Position pos)
        {
            return MapHelper.GetAdjacencyRegions(pos);
        }

        #region unit actions

        internal void FortifyUnit(UnitInfo unit)
        {
            this.Player.FortifyUnit(unit);
        }

        internal void BuildSettlement(UnitInfo unit, SettlementFlags settlementType)
        {
            this.Player.UnitBuildSettlement(unit, settlementType);
        }

        internal void DisbandUnit(UnitInfo unit)
        {
            this.Player.DisbandUnit(unit);
        }

        internal void Explore(UnitInfo unit, Position pos)
        {
            this.Player.Explore(unit, pos);
        }

        internal bool UpgradeUnit(UnitInfo unit, Template template)
        {
          bool canUpgrade = this.Player.UpgradeUnit(unit, template);
          if (canUpgrade)
              return true;
          else
              return false;
        }

        internal void Move(UnitInfo unit, Position pos)
        {
            this.Player.MoveUnitToPosition(unit, pos);
        }

        internal WinLose Attack(UnitInfo unit, Position pos)
        {
            if (this.Player.UnitAttack(unit, pos) == true)
                return WinLose.Win;
            else
                return WinLose.Lose;
        }

        #endregion

        #region settlement actions

        internal void OccupySettlement(SettlementInfo settlement)
        {
            this.Player.OccupySettlement(settlement);
        }

        internal void Abandon(SettlementInfo settlement)
        {
            this.Player.AbandonSettlement(settlement);
        }

        internal bool BuildBuildings(SettlementInfo settlement, BuildingType building)
        {
            bool flag = this.Player.BuildBuilding(settlement, building);
            if (flag == false)
            {
                MessageBox.Show("Cannot build this building, because of insufficient fund.");
                return false;
            }
            else
                return true;
        }

        internal void ChangeType(SettlementInfo settlement)
        {
            this.Player.SettlementChangeType(settlement);
        }

        internal void BuildUnit(SettlementInfo settlement, Template template)
        {
            this.Player.BuildNewUnit(settlement, template);
        }

        internal void LinkToCity(SettlementInfo settlementA, SettlementInfo settlementB)
        {
            if (settlementA.Type == SettlementFlags.City)
                this.Player.LinkToCity(settlementA, settlementB);
            else
                this.Player.LinkToCity(settlementB, settlementA);
        }

        #endregion

        #region template

        internal IEnumerable<Template> GetAllTemplates()
        {
            if (this.Player != null)
                return this.Player.Templates;
            else
                return new List<Template>();
        }

        internal void AddTemplate(Template template)
        {
            this.Player.AddTemplate(template);
        }

        // no remove in v0.3
        #endregion

        #region get units and settlements

        internal SettlementInfo GetSettlementInfoByPosition(Position pos)
        {
            return this.Player.GetSettlementInfoByPosition(pos);
        }

        internal UnitInfo GetUnitInfoByPosition(Position pos)
        {
            return this.Player.GetUnitInfosByPosition(pos).First();
        }

        /// <summary>
        /// Return all settlement belong to human player
        /// </summary>
        /// <returns></returns>
        internal IEnumerable<SettlementInfo> GetAllSettlementInfo()
        {
            if (this.Player != null)
                return this.Player.AllSettlements();
            else
                return new List<SettlementInfo>();
        }

        /// <summary>
        /// Return all unit belong to human player.
        /// </summary>
        /// <returns></returns>
        internal IEnumerable<UnitInfo> GetAllUnitInfo()
        {
            if(this.Player != null)
            return this.Player.AllUnits();
            return new List<UnitInfo>();
        }

        #endregion

        #region relationships

        internal Dictionary<uint, Dictionary<uint, DiplomaticRelationshipType>> GetRelationships()
        {
            if (this.Player != null)
                return this.Player.GetRelations();
            else
                return new Dictionary<uint, Dictionary<uint, DiplomaticRelationshipType>>();
        }

        internal void DeclearWar(uint id)
        {
            this.Player.DeclearWarOnPlayer(id);
        }
        #endregion

        #region get valid positions

        internal GameMapElement[,] GetMapElementOnCurrentScreen(
            Position upperLeftCorner,
            int gridHeight,
            int gridWidth)
        {
            GameMapElement[,] meArray = new GameMapElement[gridWidth, gridHeight];
            for(int i=0;i<gridWidth;i++)
                for (int j = 0; j < gridHeight; j++)
                {
                    Position pos = new Position(i, j) + upperLeftCorner;

                    TileType tile = this.Player.GetTileByPosition(pos);
                    SettlementInfo settlement = this.Player.GetSettlementInfoByPosition(pos);
                    IEnumerable<UnitInfo> units = this.Player.GetUnitInfosByPosition(pos);

                    GameMapElement me = new GameMapElement(tile, settlement, units);

                    meArray[i, j] = me;
                }

            return meArray;
        }

        #endregion

        #region get budget
        internal PlayerInformation GetPlayerInfo()
        {
            return new PlayerInformation(
                this.Player.ID,
                this.Player.TotalIncome,
                this.Player.Storage,
                this.Player.TotalSettlements,
                this.Player.TotalUnits);
        }
        #endregion

        internal uint GetPlayerID()
        {
            return this.Player.ID;
        }
    }
}
